单例模式是最简单的一种常用设计模式,单例模式需要确保一个类只有一个实例,这个类称为单例类(1、单例类只有一个实例,2、这个类必须自行创建这个实例,3、这个类必须自行向整个系统提供这个实例),像资源管理器(打印机)、数据库连接池等都是单例模式的实际应用。
基本原则
Java实现单例模式一般需要遵循3个原则:
- 私有化构造方法,保证外部类无法创建类实例
- 私有的静态的类型引用,保证只有一个变量引用
- 提供获取实例的方法getInstance()
实现方法
Java中单例模式有以下5种写法:恶汉式、懒汉式、双重校验锁、静态内部类、枚举类型的单例模式,下面分别介绍以下它们的Java实现和优缺点。
恶汉式
在类加载的时候就创建了实例,简单,不存在线程安全的问题,缺点是:在不需要的对象的时候也白白创建了对象,造成资源浪费。
|
|
懒汉式
在需要对象的时候才创建对象,缺点:可能造成线程不安全的问题。
|
|
双重校验锁
双重校验锁方法是在懒汉式写法上的改进,为了解决懒汉式可能出现的线程安全问题,给getInstance()
方法加上同步锁,如下:
|
|
但是这种方式效率很低下,会有很多的加锁操作,所以出现兼顾效率和线程安全的写法:双重检查锁,在synchronized
之前做一次singleton == null
判断可以减少很多加锁操作,极大提升执行效率:
|
|
PS.双重校验锁在jdk1.5以后使用volatile关键字(保证只有一个实例)才能正常达到单例效果
静态内部类
静态内部类是创建单例模式的一个很好的方法,静态的内部类只会创建一次,所以是线程安全的
|
|
枚举单例模式的写法
编写一个包含单个元素的模具类型,枚举类型中创建的实例是线程安全的,代码极简单,也是现在很推荐的一种单例模式写法
|
|
总结
恶汉式线程安全,但是不能延时加载,资源浪费;懒汉式可以延时加载,但是会存在线程安全问题,加上锁之后效率低下;双重校验锁在jdk1.5之后可以达到单例效果;静态内部类延时加载,减小内存开销,无线程安全问题;枚举不仅能够避免多线程问题,还能防止反序列化重新创建新的对象,写法简单,很好~